package hotboxr::Controller::Image;
use Moose;
use namespace::autoclean;
use MIME::Base64;
use Data::Dumper;

BEGIN {extends 'Catalyst::Controller::REST'; }

=head1 NAME

hotboxr::Controller::ImageStream - Catalyst Controller

=head1 DESCRIPTION

Catalyst Controller.

=head1 METHODS

=cut


=head2 index

=cut

#temp config til put in mongo
__PACKAGE__->config(
    ui_conf => {
        title => 'hotBoxr', autoStart => 1,
        boxes => {
            width => 240, height => 240
        },
        categories => {
            'girls_gifs' => {
                label => 'Girls + Gifs',
                formats => ['image/gif'], 
                reasons => [
                    {id => 'not_a_girl', label => "That's not a girl!"},
                    {id => 'i_see_a_dick', label => 'I see a dick!'},
                    {id => 'not_hot', label => "She's not hot!"},
                    {id => 'cum_on_face', label => "She's got some cum on her face."},
                    {id => 'just_porn', label => "This is just porn."} 
                ],
                report_text => "Thank you for braving the storm to review unverified uploads."
            },
            'small_dogs' => {
                label => 'Small Dogs',
                formats => ['image/png','image/jpeg'],
                    reasons => [
                    {id => 'not_a_dog', label => "That's not a dog!"},
                    {id => 'too_big', label => "This dog is too large."}
                ],
                report_text => "Thank you for braving the storm to review unverified uploads."
            }
        },
        ext_menu_opts => [
            { id => 'disable_overlay_highlighting', label => 'Disable Overlay Highlighting', type => 'checkbox'},
            { id => 'set_box_sizes', label => 'Box Dimensions', 'values' => ['120x120','240x240','360x360']}
        ],
        max_retrieval_iterations => 5
    }
);
sub site_options : Local : ActionClass('REST') { }
sub site_options_GET {
    my ($self, $c) = @_;
    $self->status_ok($c,entity => $self->config->{ui_conf});
    $c->forward('View::JSON');
}

sub upload : Local : ActionClass('REST') { }
sub upload_POST {
    my ($self, $c) = @_;
    my $mongo = $c->model('Mongo');

    my $category = $c->req->param('category') || '';
    if (!$category) { $c->forward('error_response',['no category']); }
    elsif (not defined $self->config->{ui_conf}->{categories}->{$category}) { 
        $c->forward('error_response',['invalid category: ' . $category]);
    } 


    my $upload = $c->request->uploads->{'filedata'};
    my $basename = $upload->basename;
    my $filename = $upload->filename;
    my $tempname = $upload->tempname;
    my $type  = $upload->type;

    $c->log->debug("category:$category|basename:$basename|filename:$filename|tempname:$tempname|type:$type");

    if (!$self->verify_type_by_category($type,$category)) { 
        $c->forward('error_response',['invalid file format: ' . $type]);
    }
    my $path = '/tmp/' . $upload->basename;
    $upload->copy_to($path);
    my $contributor_id;
    my $contributor = $mongo->get_contributor($c->req->address);
    if ($contributor->{banned} ) { $c->forward('error_response',['user is banned']); } 
    else {
        $contributor_id = $contributor->{_id};       
    }

    my $image_oid = eval { $mongo->store_image($path,$type,$contributor_id,$category) };
    if ($image_oid) {
        $mongo->increment('contributors','num_uploads',$contributor_id);
        $self->status_ok($c,entity => { upload_success => 1, image_oid => $image_oid->to_string });
        $c->forward('View::JSON');
    } elsif ($@) {
        my $err = ($@ =~ /duplicate key error index/ ? 'duplicate image' : "mongo threw err: $@");
        $c->forward('error_response',[$err]);
    }
    else { $c->forward('error_response',['failed to upload image']);   }    
}

sub verify_type_by_category : Private {
    my ($self,$type,$category) = @_;
    my $allowed = $self->config->{ui_conf}->{categories}->{$category}->{formats};
    return ($type ~~ @$allowed);
}

sub random_image : Local : ActionClass('REST') { }

sub random_image_GET {
    my ($self,$c) = @_;
    my $mongo = $c->model('Mongo');
    my $category = $c->req->param('category') || 'all';
    my $allow_unverified = $c->req->param('allow_unverified') || 0;
    my $got_good_image = 0;
    my $verified_by_user = 0;
    my $verified = 0; 
    my $attempts = 0;
    my $image; my $err = '';

    while (!$got_good_image) {
        $attempts++;
        $image = $mongo->get_random_image($category,$allow_unverified);
        if (!defined $image) { $err = 'failed to get random image'; last; }
        $verified = $image->{info}->{verified};
        if ($allow_unverified) {
            $c->log->debug($image->{info}->{_id}->to_string . " is verified? " . $verified);
            my $report = $mongo->check_if_already_reported($mongo->find_contributor_by_ip($c->req->address), $image->{info}->{_id});
            if (defined $report) {
                if ($report->{type} eq 'verify') { $verified = 1; $verified_by_user = 1;}
                $got_good_image = 1 unless $report->{type} eq 'infract'; #dont show unverified img if they reported it.
            } else {
                $c->log->debug("No Report Defined");
                $got_good_image = 1; 
            }
            $c->log->debug("got good? $got_good_image");
            $err = 'max iterations did not produce usable image' if $attempts >= $self->config->{ui_conf}->{max_retrieval_iterations};
            last if $err;
        } else { $got_good_image = 1; }
    }

    $c->log->debug("VERIFIED: $verified");
    $c->forward('error_response',[$err]) if $err;
    my $b64 = encode_base64($image->slurp());

    $c->log->debug("random image is :" .  $image->{info}->{_id}->to_string . " and base 64 is " . length($b64) . " chars");
    $self->status_ok($c,entity => { 
        success => 1, 
        image => {
            base64 => $b64, 
            type => $image->{info}->{file_type}, 
            id => $image->{info}->{_id}->to_string,
            verified => $verified*1, #js numbers yo
            verified_by_user => $verified_by_user*1
        }
    });
    $c->forward('View::JSON');
}

#sub verify : Local : ActionClass('REST') { }
#sub verify_GET {
#    my ($self,$c) = @_;
#    my $image_id = $c->req->param('image_id') || undef;
#    my $mongo = $c->model('Mongo') || undef;;
#    $c->forward('error_response',['no image id']) if not defined $image_id;
#    $c->forward('error_response',['no mongo']) if not defined $mongo;
#    $c->log->debug("verifying $image_id");
#
#    my $contributor = $mongo->get_contributor($c->req->address);
#    $c->log->debug("contributor is " . (defined $contributor ? '' : 'not ') . " defined");
#    if ($contributor->{banned}) { $c->forward('error_response',['user is banned']) };
#    if($mongo->add_report($contributor,$image_id,'verify','unweighted')) {
#        $c->log->debug("added report");
#        $self->status_ok($c, entity => { success => 1 });
#        $c->forward('View::JSON');
#    } else { $c->forward('error_response',['user has already made report for this image']); }
#}

sub verify : Local : ActionClass('REST') { }
sub verify_GET {
    my ($self, $c) = @_;
    my $p = $self->_validate_params($c,[qw/image_id/]);
    $p->{type} = 'verify';
##future: determine user's contribution weight & apply to score
    $p->{report_reason} = 'unweighted';
##
    $c->forward('send_report',[$p]);
}

sub report : Local : ActionClass('REST') { }
sub report_GET {
    my ($self,$c) = @_;
    my $p = $self->_validate_params($c,[qw/image_id report_reason category/]);
    $p->{type} = 'infract';
    $c->forward('send_report',[$p]);
}

sub send_report : Private {
    my ($self,$c,@data) = @_;
    my $p = $data[0];
    my $mongo = $self->_validate_db($c,'Mongo');
    $c->log->debug("$p->{type}: reporting $p->{image_id} of category $p->{category} for $p->{report_reason}");

    my $contributor = $mongo->get_contributor($c->req->address);
    $c->log->debug("contributor is " . (defined $contributor ? '' : 'not ') . " defined");
    if ($contributor->{banned}) { $c->forward('error_response',['user is banned']) };
    if($mongo->add_report($contributor,$p->{image_id},$p->{type},$p->{report_reason})) {
        $c->log->debug("added report");
        $self->status_ok($c, entity => { success => 1 });
        $c->forward('View::JSON');
    } else { $c->forward('error_response',['user has already made report for this image']); }
}

sub _validate_db : Private {
    my ($self,$c,$name) = @_;
    my $db = $c->model($name) || undef;
    $c->forward('error_response',['no ' . $name]) if not defined $db;
    return $db;    
}

sub _validate_params : Private {
    my ($self,$c,$req) = @_;
    my %ret = ();
    my @missing = ();
    foreach my $p (@$req) {
        my $v = $c->req->param($p) || '';
        push @missing,$p if !$v;
        $ret{$p} = $v;
    }
    $c->forward('error_response',['missing params: ' . join(', ', @missing)]) if scalar @missing > 0;
    return \%ret; 
}

sub error_response : Private {
    my ($self, $c, @data) = @_;
    $c->log->debug("error_response:" . Dumper(\@data));
    $self->status_ok($c, entity => { webservice_error => $data[0]});
    $c->forward('View::JSON');
    $c->detach();
}


=head1 AUTHOR

A clever guy

=head1 LICENSE

This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

__PACKAGE__->meta->make_immutable;

1;
